home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d20 / msgq160s.arc / MSGEDQ.C < prev    next >
Text File  |  1991-10-26  |  18KB  |  885 lines

  1. /*
  2.  * MSGEDQ.C - Main program
  3.  *
  4.  * Msged/Q message editor for QuickBBS  Copyright 1990 by P.J. Muller
  5.  *
  6.  */
  7.  
  8. #include <process.h>
  9. #include <stdio.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <dos.h>
  14. #if defined(__MSC__) || defined(__TURBOC__) || defined(__JPIC__)
  15. #include <fcntl.h>
  16. #endif
  17.  
  18. #define MAIN
  19. #include "msged.h"
  20. #include "screen.h"
  21. #include "bmg.h"
  22. #include "maincmds.h"
  23. #include "qmsgbase.h"
  24. #include "shell.h"
  25.  
  26. #if 0
  27. #ifdef __ZTC__
  28. unsigned _stack = 4096;
  29. #endif
  30. #endif
  31.  
  32. #if defined(__TURBOC__)
  33. unsigned int _stklen = 4096;    /* Turbo C min. stack size */
  34. #endif
  35.  
  36. #ifdef __JPIC__
  37. int _ISDST = 0;                 /* hack */
  38. #endif
  39.  
  40. #define ENDFREQ 550        /* Hz */
  41. #define ENDLEN 1        /* 1/18.2 s */
  42.  
  43. #define S_HEAD 1
  44. #define S_TEXT 2
  45. #define S_BOTH (S_TEXT|S_HEAD)
  46.  
  47. static void highest(void);
  48. static int command;            /* keyboard command */
  49. static int direction = RIGHT;
  50. static int root = 0;            /* root message of a thread */
  51. static int back = 0;
  52.  
  53. static int start(int argc, char *argv[]);
  54. static void empty(void);
  55. static void gotomsg(int i);
  56. static void srch(int what);        /* 1-header, 2-text, 3-both */
  57. static void toarea(int n);
  58. static void retry(void);
  59.  
  60. void go_last()
  61. {
  62.   setcur(CurBoard, lastreadmsg(CurBoard));
  63.   root = curmsg(CurBoard);
  64. }
  65.  
  66. void escquit()
  67. {
  68.   if (confirm(confirmations))
  69.     cleanup();
  70. }
  71.  
  72. void deletemsg()
  73. {
  74.   if (!confirm(confirmations))
  75.     return;
  76.  
  77.   msgdelete(curmsg(CurBoard),arealist[area].echomail,arealist[area].netmail);
  78.  
  79.   if (direction == LEFT)
  80.     left();        /* for Peter */
  81. }
  82.  
  83. void link_from()
  84. {
  85.   if (!msgat(CurBoard,message.header.reply))
  86.     return;
  87.  
  88.   back = curmsg(CurBoard);
  89.   setcur(CurBoard,message.header.reply);
  90. }
  91.  
  92. void link_to()
  93. {
  94.   if (!msgat(CurBoard,message.header.up))
  95.     return;
  96.  
  97.   back = curmsg(CurBoard);
  98.   setcur(CurBoard,message.header.up);
  99. }
  100.  
  101. void marklast()
  102. {
  103.   setlastread(CurBoard,curmsg(CurBoard));
  104. }
  105.  
  106. void view()
  107. {
  108.   shownotes = !shownotes;
  109. #ifdef SEENBY
  110.   if (shownotes)
  111.     seenbys = shownotes;
  112. #endif
  113. }
  114.  
  115. void go_root()
  116. {
  117.   if (!msgat(CurBoard,root))
  118.     return;
  119.  
  120.   back = curmsg(CurBoard);
  121.   setcur(CurBoard,root);
  122.  
  123.   highest();
  124. }
  125.  
  126. void rotate()
  127. {
  128.   rot13 = (rot13 + 1) % 4;
  129. }
  130.  
  131. void togaddr()
  132. {
  133.   techie = !techie;
  134. } /* togaddr */
  135.  
  136. void go_dos()
  137. {
  138. #ifndef MINI
  139.   os();
  140. #endif
  141. }
  142.  
  143. void main(int argc, char *argv[])
  144. {
  145.   arealist = NULL;
  146.   msgbuf.first = NULL;
  147.  
  148. #if defined(__MSC__) || defined(__TURBOC__) || defined(__JPIC__)
  149.   _fmode = (unsigned int) O_BINARY;    /* default open mode - binary */
  150. #endif
  151.  
  152.   command = start(argc,argv);
  153.  
  154.   while (1) {        /* endless loop... exit is through cleanup */
  155.     if (command & 0xff) {
  156.       if (isdigit(command))
  157.     gotomsg(command - 0x30);
  158.       else if (mainckeys[command])
  159.     mainckeys[command & 0xff]();
  160.     }
  161.     else if (mainakeys[command >> 8])
  162.       mainakeys[command >> 8]();
  163.  
  164.     if (countmsg(CurBoard) < 1) {
  165.       empty();
  166.       command = getkey();
  167.     }
  168.     else {
  169.       int last = lastmsg(CurBoard);
  170.  
  171.       if (!msgat(CurBoard,curmsg(CurBoard))) {    /* e.g. after delete */
  172.     setcur(CurBoard,msgnext(CurBoard,curmsg(CurBoard)));
  173.     highest();
  174.       } /* if */
  175.  
  176.       if (lastreadmsg(CurBoard) > last)
  177.     setlastread(CurBoard,last);
  178.       if (curmsg(CurBoard) > last)
  179.     setcur(CurBoard,last);
  180.  
  181.       if (!readmsg(&message, curmsg(CurBoard))) {
  182.     retry();
  183.     command = direction;
  184.     continue;
  185.       }
  186.       command = showmsg(message);
  187.     } /* else */
  188.   } /* while */
  189. } /* main */
  190.  
  191. static void retry(void)
  192. {
  193.   int ch;
  194.  
  195.   gotoxy(9,1);
  196.   clreol();
  197.   set_color(co_warn);
  198.   bputs("Error reading message, (R)etry or (A)bort? ");
  199.   video_update();
  200.  
  201.   do {
  202.     ch = getkey() & 0x7f;
  203.     ch = tolower(ch);        /* tolower might be a macro */
  204.   } while ((ch != 'r') && (ch != 'a'));
  205.  
  206.   bputc((char) ch);
  207.   set_color(co_normal);
  208.  
  209.   if (ch == 'a')
  210.     cleanup();
  211. } /* retry */
  212.  
  213. void cleanup()
  214. {
  215.   int echomail = 0, netmail = 0;
  216.   int result;
  217.  
  218.   cls();
  219.  
  220.   for (area = 0; area < areas; area++) {
  221.     if (arealist[area].echomail)
  222.       echomail |= arealist[area].new;
  223.  
  224.     if (arealist[area].netmail)
  225.       netmail |= arealist[area].new;
  226.   } /* for */
  227.  
  228.   if (!closemsgbase()) {
  229.     set_color(co_warn);
  230.     bputs("Error closing message base.");
  231.     set_color(co_normal);
  232.     gotoxy(1,2);
  233.   } /* if */
  234.  
  235.   if (useusersbbs)        /* update USERS.BBS */
  236.     updatehigh(usernum, highmsgread);
  237.  
  238.   set_color(co_hilite);
  239.   if (echomail && netmail) {
  240.     bputs("New Echomail and Netmail entered.");
  241.     result = 3;
  242.   } else if (echomail) {
  243.     bputs("New Echomail entered.");
  244.     result = 2;
  245.   } else if (netmail) {
  246.     bputs("New Netmail entered.");
  247.     result = 1;
  248.   } else {
  249.     bputs("No new net- or echomail entered.");
  250.     result = 0;
  251.   } /* else */
  252.   set_color(co_normal);
  253.   gotoxy(1,3);
  254.   bprintf("* Exiting from Msged/Q with errorlevel %d.", result);
  255.   gotoxy(1,4);
  256.   video_update();
  257.   video_end();
  258.  
  259.   exit(result);
  260. } /* cleanup */
  261.  
  262. void halt(int status)
  263. {
  264.   if (status != 0)
  265.     fprintf(stderr,"\nExiting with errorlevel %d\n",status);
  266.   exit(status);
  267. } /* halt */
  268.  
  269. void fatal(char *s)
  270. {
  271.   fprintf(stderr, "\n%s\n", s);
  272.   fprintf(stderr, "Press <Return> to exit.\n");
  273.   while (getchar() != '\n') /* nothing */;
  274.   cleanup();
  275. } /* fatal */
  276.  
  277. void outamemory()
  278. {
  279.   fatal("I've run out of memory!");
  280. } /* outamemory */
  281.  
  282. static void empty()
  283. {
  284.   cls();
  285.   gotoxy(3, maxy / 2);
  286.   set_color(co_hilite);
  287.   bprintf("No messages in '%s'!", arealist[area].description);
  288.   set_color(co_normal);
  289. } /* empty */
  290.  
  291. static void search()
  292. {
  293.   srch(S_BOTH);
  294. } /* srchall */
  295.  
  296. static void srchhdr()
  297. {
  298.   srch(S_HEAD);
  299. } /* srchhdr */
  300.  
  301. static void srch(int what)
  302. {
  303.   static bmgARG pattern;
  304.   static char prompt[bmgMAXPAT];
  305.   static char patstr[bmgMAXPAT];
  306.   static int lastfound = 0;
  307.   MSGHEADER hdr;
  308.   int tmp2;
  309.   char *s;
  310.   int tmp;
  311.   int curarea = area;
  312.  
  313.   gotoxy(9,1);
  314.   clreol();
  315.   set_color(co_info);
  316.   bputs("Find: ");
  317.   set_color(co_normal);
  318.   if (bgets(prompt,sizeof(prompt)) == ABORT)
  319.     return;
  320.  
  321.   if (strcmpl(prompt,patstr) != 0) {        /* changed, so recompile */
  322.     memset(patstr,0,sizeof(patstr));
  323.     memset(&pattern,0,sizeof(bmgARG));
  324.     strncpy(patstr,prompt,sizeof(prompt));
  325.     bmgCompile(patstr,&pattern,TRUE);
  326.     lastfound = 0;
  327.   } /* if */
  328.  
  329.   gotoxy(9,1);
  330.   clreol();
  331.  
  332.   set_color(co_info);
  333.   for (;;) {
  334.     do {
  335.       s = NULL;
  336.       tmp = curmsg(CurBoard);
  337.       if (readheader(tmp, &hdr)) {
  338.     if (what & S_TEXT)
  339.       s = readtext(&hdr);
  340.     if (what & S_HEAD) {
  341.       if (s == NULL) {
  342.         if ((s = malloc(36+36+73+1)) != NULL)
  343.           *s = EOS;
  344.       } else {
  345.         s = realloc(s,strlen(s)+1 + 36+36+73+1);
  346.       } /* else */
  347.  
  348.       if (s != NULL) {
  349.         strcat(s, hdr.to);
  350.         strcat(s, hdr.from);
  351.         strcat(s, hdr.subj);
  352.       } /* if */
  353.  
  354.     } /* if */
  355.       } /* if */
  356.  
  357.       if (s != NULL) {
  358.     gotoxy(9,1);
  359.     bprintf("Looking at %s #%d for \"%s\"",
  360.         arealist[area].description,tmp,prompt);
  361.     video_update();
  362.     clreol();    /* vvv is ignored and 's' is changed */
  363.     tmp2 = bmgSearch(s,strlen(s),&pattern);
  364.     ptrfree(s); s = NULL;
  365.  
  366.     if (tmp2 && (lastfound != tmp)) {    /* found new one */
  367.       lastfound = tmp;
  368.       set_color(co_normal);
  369.       return;
  370.     } /* if */
  371.       } /* if */
  372.  
  373.       if (keypressed()) {
  374.     if (getkey() == ABORT) {
  375.       set_color(co_normal);
  376.       return;
  377.     } /* if */
  378.       } /* if */
  379.  
  380.       tmp = msgnext(CurBoard, tmp2 = tmp);
  381.       if (tmp != 0)
  382.     setcur(CurBoard,tmp);
  383.     } while ((tmp != 0) && (tmp != tmp2));
  384.  
  385.     if (!globsrch) break;    /* not global search, exit */
  386.  
  387.     if (++area >= areas)
  388.       area = 0;
  389.     if (area == curarea) break;    /* searched through all */
  390.     tmp = firstmsg(CurBoard);    /* skip to first message of next board */
  391.     setcur(CurBoard,tmp);
  392.   } /* forever */
  393.  
  394.   beep(0,0);
  395.  
  396.   set_color(co_normal);
  397. } /* srch */
  398.  
  399. BOOLEAN confirm(int confirmations)
  400. {
  401.   int ch;
  402.  
  403.   if (!confirmations)
  404.     return(TRUE);
  405.  
  406.   gotoxy(9,1);
  407.   clreol();
  408.   set_color(co_warn);
  409.   bputs("*warning* ");
  410.   bputs("Do you really want to do this? (y/n) ");
  411.   video_update();
  412.  
  413.   do {
  414.     ch = getkey() & 0x7f;
  415.     ch = tolower(ch);        /* tolower might be a macro */
  416.   } while ((ch != 'y') && (ch != 'n'));
  417.  
  418.   bputc((char) ch);
  419.   set_color(co_normal);
  420.   return(ch == 'y');
  421. } /* confirm */
  422.  
  423. /*
  424.  * Set highest message read and set 'root' to current message
  425.  * There may be problems here, with msgnum and filemsg ...
  426.  * ... think about it sometime
  427.  */
  428.  
  429. void highest()
  430. {
  431.   if (msgat(CurBoard,curmsg(CurBoard)))
  432.     root = curmsg(CurBoard);        /* global */
  433.  
  434.   if (root > lastreadmsg(CurBoard))
  435.     setlastread(CurBoard, root);
  436.  
  437. } /* highest */
  438.  
  439. void left()
  440. {
  441.   int temp;
  442.  
  443.   back = curmsg(CurBoard);
  444.   direction = LEFT;
  445.  
  446.   if (back <= firstmsg(CurBoard))
  447.     beep(0,0);    /* must check here, msgprev doesn't give error */
  448.  
  449.   if ((temp = msgprev(CurBoard, back)) == 0)
  450.     temp = firstmsg(CurBoard);
  451.   setcur(CurBoard, temp);
  452.  
  453.   highest();    /* set root */
  454. } /* left */
  455.  
  456. void right()
  457. {
  458.   int temp;
  459.  
  460.   back = curmsg(CurBoard);
  461.   direction = RIGHT;
  462.  
  463.   if (back >= lastmsg(CurBoard))
  464.     beep(0,0);    /* must check here, msgnext doesn't give error */
  465.  
  466.   if ((temp = msgnext(CurBoard, back)) == 0)
  467.     temp = lastmsg(CurBoard);
  468.   setcur(CurBoard, temp);
  469.  
  470.   highest();
  471. } /* right */
  472.  
  473. void movetop()
  474. {
  475.   back = curmsg(CurBoard);
  476.   direction = LEFT;
  477.  
  478.   setcur(CurBoard,lastmsg(CurBoard));
  479.  
  480.   highest();
  481. } /* movetop */
  482.  
  483. void movebot()
  484. {
  485.   back = curmsg(CurBoard);
  486.   direction = RIGHT;
  487.  
  488.   setcur(CurBoard,firstmsg(CurBoard));
  489.  
  490.   highest();        /* set root */
  491. } /* movebot */
  492.  
  493. void enter()
  494. {
  495.   if (direction == RIGHT)
  496.     right();
  497.   else
  498.     left();
  499. } /* enter */
  500.  
  501. void nextto()
  502. {
  503.   int new;
  504.   int look = area;
  505.   int startarea = area;
  506.  
  507.   set_color(co_info);
  508.   do {
  509.     gotoxy(9,1);
  510.     bprintf("Looking for new mail to you in '%s'",arealist[look].description);
  511.     video_update();
  512.     clreol();
  513.  
  514.     new = searchto(arealist[look].board, curmsg(arealist[look].board), username);
  515.  
  516.     if (keypressed()) {
  517.       if (getkey() == ABORT) {
  518.     set_color(co_normal);
  519.     return;
  520.       } /* if */
  521.     } /* if */
  522.   } while ((globsrch) && (new == -1) &&
  523.        ((++look >= areas ? look = 0 : look) != startarea));
  524.  
  525.   set_color(co_normal);
  526.  
  527.   if (new == -1) {
  528.     beep(0,0);
  529.     return;
  530.   } /* while */
  531.  
  532.   area = look;
  533.   setcur(CurBoard,new);
  534.   /* highest(); */    /* not here */
  535. } /* nextto */
  536.  
  537. static void gotomsg(int i)
  538. {
  539.   int f,l;
  540.  
  541.   f = /* firstmsg(CurBoard) */ 0;        /* 8/2/90 */
  542.   l = lastmsg(CurBoard);
  543.  
  544.   gotoxy(9, 1);
  545.   clreol();
  546.   set_color(co_info);
  547.   bprintf("Goto Message #? (%d-%d) ", f, l);
  548.   set_color(co_normal);
  549.   back = curmsg(CurBoard);
  550.   i = getnum(f, l, i);
  551.   if (i == 0)                /* ignore it */
  552.     return;
  553.  
  554.   if (!msgat(CurBoard,i))
  555.     i = msgnext(CurBoard,i);
  556.   setcur(CurBoard, i);
  557.  
  558.   if (!msgat(CurBoard,i))
  559.     setcur(CurBoard, back);
  560.   else
  561.     highest();
  562. } /* gotomsg */
  563.  
  564. void newarea()
  565. {
  566.   int newarea;
  567.  
  568.   if (!flushmsgbase())
  569.     fatal("Error writing message base");
  570.  
  571.   if (areas < 2)
  572.     return;
  573.  
  574.   newarea = selectarea(NULL);
  575.   if (newarea != -1)
  576.     toarea(newarea);        /* show menu */
  577. } /* newarea */
  578.  
  579. void nextarea()
  580. {
  581.   int look = area;
  582.  
  583.             /* look for next board with mail */
  584.   while ((++look >= areas ? look = 0 : look) != area)
  585.     if (lastmsg(arealist[look].board) > lastreadmsg(arealist[look].board))
  586.       break;
  587.  
  588.   if (look != area) {
  589.     toarea(look);
  590.   } else {
  591.     toarea(0);        /* go to first area */
  592.     beep(0,0);
  593.   }
  594. } /* nextarea */
  595.  
  596. void prevarea()
  597. {
  598.   int look = area;
  599.  
  600.             /* look for prev board with mail */
  601.   while ((--look < 0 ? look = areas-1 : look) != area)
  602.     if (lastmsg(arealist[look].board) > lastreadmsg(arealist[look].board))
  603.       break;
  604.  
  605.   if (look != area)
  606.     toarea(look);
  607.   else
  608.     beep(0,0);
  609. } /* prevarea */
  610.  
  611. void uparea()
  612. {
  613.   toarea(area+1 >= areas ? 0 : area+1);
  614. } /* uparea */
  615.  
  616. void downarea()
  617. {
  618.   toarea(area <= 0 ? areas-1 : area-1);
  619. } /* downarea */
  620.  
  621. static void toarea(int n)
  622. {
  623.   area = n;
  624.   override = FALSE;
  625.   direction = RIGHT;
  626.   back = root = curmsg(CurBoard);
  627.   clearbuffer(&msgbuf);
  628. } /* toarea */
  629.  
  630. static void checkbase(void)
  631. {
  632.   BYTE board;
  633.   int result;
  634.  
  635.   gotoxy(1, maxy-3);
  636.   bputs("Checking message base... ");
  637.   video_update();
  638.  
  639.   result = checkmsgbase(&board);
  640.  
  641.   if (result == CHK_NOERR) {
  642.     bputs("No errors found.");
  643.   } else {
  644.     char *msg = NULL;
  645.  
  646.     switch (result) {
  647.       case CHK_NONINC:
  648.     msg = "Non-increasing numbers found in board %d";
  649.     break;
  650.       case CHK_COUNTS:
  651.     msg = "MSGINFO.BBS and MSGIDX.BBS differ in board %d";
  652.     break;
  653.       case CHK_HDR:
  654.     msg = "Length of MSGHDR.BBS differs from MSGIDX.BBS";
  655.     break;
  656.       case CHK_TO:
  657.     msg = "Length of MSGTOIDX.BBS differs from MSGIDX.BBS";
  658.     break;
  659.     } /* switch */
  660.  
  661.     gotoxy(1, maxy-3);
  662.     set_color(co_warn);
  663.     bputs("Error: ");
  664.     bprintf(msg, board);
  665.     clreol();
  666.     gotoxy(1, maxy-2);
  667.     bputs("You should exit and run MSGPACK -I to rebuild your index files.");
  668.     set_color(co_normal);
  669.   } /* else */
  670.  
  671. } /* checkbase */
  672.  
  673. static void usage_exit(void)
  674. {
  675.   printf("\nUsage: MsgedQ [switches] [configfile [areasfile]]\n\n");
  676.   printf("  -q       Read QuickBBS config files\n");
  677.   printf("  -r       Read RemoteAccess config files\n");
  678. #ifdef DBRIDGE
  679.   printf("  -b       Read D'Bridge config files\n");
  680. #endif
  681.   printf("  -d       Config trace mode for debugging\n");
  682.   printf("  -nPath   Write new config file and define Path as netmail directory\n");
  683.   printf("  -uName   Override username from config file (use \"_\" for space)\n");
  684.   printf("  -p       Protect netmail\n");
  685.   exit(255);
  686. } /* usage_exit */
  687.  
  688. static int start(int argc, char *argv[])
  689. {
  690.   char *uname = NULL;
  691.   char *cfg = NULL, *afn = NULL;
  692.  
  693.   printf("Msged/Q " VERSION "  Copyright 1991  Pieter J. Muller\n");
  694.  
  695.   configdebug = quicksysop = rastruct = protectnet = FALSE;
  696. #ifdef DBRIDGE
  697.   dbridgestruct = FALSE;
  698. #endif
  699.   useusersbbs = TRUE;        /* could be configurable */
  700.  
  701.   while (--argc) {
  702.     if (**(++argv) == '-') {
  703.       switch (tolower(argv[0][1])) {
  704.     case 'n':
  705.       newnetpath = &argv[0][2];
  706.       createconfig = (*newnetpath != EOS);
  707.       if (createconfig) configdebug = TRUE;
  708.       if (createconfig && (newnetpath[strlen(newnetpath)-1] != '\\')) {
  709.         newnetpath = malloc(strlen(newnetpath)+2);
  710.         strcpy(newnetpath,&argv[0][2]);
  711.         strcat(newnetpath,"\\");
  712.       } /* if */
  713.       break;
  714.  
  715.     case 'u': {  char *c;
  716.       uname = &argv[0][2];
  717.       for (c = uname; *c != EOS; ++c)
  718.         if (*c == '_') *c = ' ';
  719.       break;
  720.     }
  721.  
  722.     case 'p':
  723.       protectnet = TRUE;
  724.       break;
  725.  
  726.     case 'd':
  727.       configdebug = TRUE;
  728.       break;
  729.  
  730.     case 'q':
  731.       quicksysop = TRUE;
  732.       break;
  733.  
  734.     case 'r':
  735.       rastruct = TRUE;
  736.       break;
  737.  
  738. #ifdef DBRIDGE
  739.     case 'b':
  740.       dbridgestruct = TRUE;
  741.       break;
  742. #endif
  743.  
  744.     case 'h':
  745.     case '?':
  746.       usage_exit();
  747.  
  748.     default:
  749.       printf("Unknown switch '-%c'\n", argv[0][1]);
  750.       break;
  751.       } /* switch */
  752.     } else {
  753.       if (cfg == NULL)
  754.     cfg = *argv;
  755.       else
  756.     if (afn == NULL)
  757.       afn = *argv;
  758.     } /* else */
  759.   } /* while */
  760.  
  761.   /* (void)putenv("PROMPT=Msged/Q $P$G"); */
  762.  
  763.   printf("Initialising...\n");
  764.   memset(&message, 0, sizeof(message));
  765.   opening(cfg,afn,uname);
  766.  
  767.   message.to = thisnode[CurAKA];
  768.   if (message.to.domain != NULL)
  769.     message.to.domain = strdup(message.to.domain);
  770.  
  771.   if (!openmsgbase())
  772.     fatal("Cannot open message base.");
  773.  
  774.   checkbase();
  775.  
  776.   gotoxy(1, maxy);
  777.   bputs("Scanning for new mail....");
  778.   video_update();
  779.  
  780.   area = areas-1;            /* search forward from last area */
  781.   nextarea();                /* next area with new mail */
  782.  
  783.   gotoxy(1, maxy);
  784.   bputs("Press any key to continue....");
  785.   clreol();
  786.   video_update();
  787.   getkey();
  788.  
  789.   return(KAREA);
  790.  
  791. } /* start */
  792.  
  793. #ifdef ZAPTHISOUT
  794. /*
  795.  * Execute a Dos command
  796.  * If path==NULL, execute COMSPEC
  797.  * command may be NULL
  798.  * Return TRUE iff ok
  799.  */
  800.  
  801. BOOLEAN shell(char *path, char *command)
  802. {
  803.   if (path == NULL)
  804.     if ((path = getenv("COMSPEC")) == NULL)
  805.       return FALSE;
  806.  
  807.   if (spawnlp(P_WAIT, path, path, command, NULL) == -1)
  808.     return FALSE;
  809.  
  810.   return TRUE;
  811. } /* shell */
  812. #endif
  813.  
  814. #ifndef MINI
  815. static void far shell_msg(char swapmode, long amount)
  816. {
  817.   if (swapmode != SWAP_NONE) {
  818.     bprintf("Swapping %ld bytes to %s\n", amount,
  819.         swapmode==SWAP_EMS ? "EMS" : "disk");
  820.     gotoxy(1, wherey()+1);
  821.     video_update();
  822.   }
  823. } /* shell_msg */
  824.  
  825. void os()
  826. {
  827.   void *temp = shell_message;
  828.   shell_message = shell_msg;
  829.  
  830.   cls();
  831.   if (!flushmsgbase())
  832.     fatal("Error writing message base");
  833.  
  834.   bputs("Type EXIT to return to Msged/Q.");
  835.   gotoxy(1,3);  video_update();
  836.   if (!shell(NULL,NULL)) {
  837.     gotoxy(9,1);
  838.     set_color(co_warn);
  839.     bputs("Could not shell, press any key");
  840.     clreol();
  841.     set_color(co_normal);
  842.     video_update();
  843.     (void)getkey();
  844.   } /* if */
  845.  
  846.   shell_message = temp;
  847.   video_init();
  848. } /* os */
  849. #endif
  850.  
  851. void beep(int freq, int len)
  852. {
  853. #if defined(__TURBOC__) || defined(__JPIC__)
  854.   static char state = 0;
  855.  
  856. #define timer() (*(long far *)MK_FP(0, 0x046c))
  857. #define waitedge()      { long v = timer();  while (v == timer()) /* */; }
  858.  
  859.   if (!beepson) return;
  860.  
  861.   if (state == 0) {
  862.     long value = timer();
  863.     sleep(1);
  864.     if (value == timer())
  865.       state = 1;        /* disable all further beep calls */
  866.     else
  867.       state = 2;        /* enable normal working */
  868.   } /* if */
  869.   if (state == 1) return;    /* beeps disabled */
  870.  
  871.   if (freq == 0) freq = ENDFREQ;
  872.   if (len == 0) len = ENDLEN;
  873.  
  874.   waitedge();
  875.   sound(freq);
  876.   while (len--)
  877.     waitedge();
  878.   nosound();
  879. #endif
  880. } /* beep */
  881.  
  882. #ifndef SETTINGS
  883. void settings() {}
  884. #endif
  885.